import type { UnConfig, UnData, UnInstance, UnMethod } from '@uni-helper/uni-network'
import $config from '@/config'
import { useUserStore } from '@/stores/user'
import { isMatch } from '@/utils/is'
import {
  un,

} from '@uni-helper/uni-network'
import errorText from './error'

class UniHttp {
  constructor() {
    this.httpInterceptorsRequest()
    this.httpInterceptorsResponse()
  }

  /** `token`过期后，暂存待执行的请求 */
  private static requests: ((token: string) => void)[] = []

  /** 防止重复刷新`token` */
  private static isRefreshing = false

  /** 当前实例对象 */
  private static instance: UnInstance<UnData, UnData> = un.create({
    baseUrl: '',
    headers: {
      'Accept': 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      'X-Requested-With': 'XMLHttpRequest',
    },
    timeout: 15000,
  })

  /** 重连原始请求 */
  private static retryOriginalRequest(config: UnConfig) {
    return new Promise((resolve) => {
      UniHttp.requests.push((token: string) => {
        config.headers = {
          Authorization: `Bearer ${token}`,
          ...config.headers,
        }
        resolve(config)
      })
    })
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    UniHttp.instance.interceptors.request.use(
      async (config): Promise<any> => {
        const configUrl = config.url || ''
        // 用户TOKEN
        const localToken = useUserStore().readUserToken
        /** 请求白名单，放置一些不需要`token`的接口（通过设置请求白名单，防止`token`过期后再请求造成的死循环问题） */
        return isMatch($config.service.whiteList, configUrl)
          ? config
          : new Promise((resolve) => {
            if (localToken) {
              const now = new Date().getTime()
              const expired
                  = Number.parseInt(localToken.expires.toString()) - now <= 0
              if (expired) {
                if (!UniHttp.isRefreshing) {
                  UniHttp.isRefreshing = true
                  // token过期刷新
                  useUserStore()
                    .refreshToken(localToken.refreshToken)
                    .then((res) => {
                      const token = res.accessToken
                      config.headers = {
                        Authorization: localToken
                          ? `Bearer ${localToken.accessToken}`
                          : undefined,
                        ...config.headers,
                      }
                      UniHttp.requests.forEach(cb => cb(token))
                      UniHttp.requests = []
                    })
                    .finally(() => {
                      UniHttp.isRefreshing = false
                    })
                }
                resolve(UniHttp.retryOriginalRequest(config))
              }
              else {
                config.headers = {
                  Authorization: localToken
                    ? `Bearer ${localToken.accessToken}`
                    : undefined,
                  ...config.headers,
                }
                resolve(config)
              }
            }
            else {
              resolve(config)
            }
          })
      },
      (error) => {
        return Promise.reject(error)
      },
    )
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    UniHttp.instance.interceptors.response.use(
      (response) => {
        // const data = response as IUnResponse
        //
        // if (response.config?.showError ?? true) {
        //   showNetworkError({
        //     response: response as unknown as IUnResponse,
        //     error: data?.data as unknown as IUnError,
        //     type: data.config?.showErrorType,
        //   })
        // }
        return response
      },
      (error) => {
        // 如果后端返回了错误消息，直接返回
        const data: any = error?.response?.data
        error.message = errorText(error.status, data.message ?? error.message)
        if (error.status === 401) {
          // 认证失败，直接退出
          useUserStore().forceLogoutModal(error.message)
          return
        }
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject(error)
      },
    )
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: UnMethod,
    url: string,
    param?: object,
    unConfig?: UnConfig,
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...unConfig,
    } as UnConfig
    return new Promise((resolve, reject) => {
      config.url = $config.service.api.url(config)
      UniHttp.instance(config)
        .then((response) => {
          const res = $config.service.api.response(response)
          resolve(res as any)
        })
        .catch((error) => {
          reject(error)
        })
    })
  }

  /** 单独抽离的`post`工具函数 */
  public post<T>(
    url: string,
    params?: object,
    unConfig?: UnConfig,
  ): Promise<T> {
    return this.request<T>('post', url, params, unConfig)
  }

  /** 单独抽离的`get`工具函数 */
  public get<T>(
    url: string,
    params?: object,
    config?: UnConfig,
  ): Promise<T> {
    return this.request<T>('get', url, params, config)
  }
}

export const http = new UniHttp()
